一些shell的note
basename命令和dirname命令
basename:从文件名中去掉路径信息, 只打印出文件名. 结构 basename $0
可以让脚本知道它自己的名字
可以用来显示用法信息, 比如如果你调用脚本的时候缺少参数, 可以使用如下语句:
echo "Usage: basename $0
arg1 arg2 ... argn"
$0:显示会包括当前脚本或命令的路径
dirname:从带路径的文件名中去掉文件名, 只打印出路径信息
basename 和 dirname 可以操作任意字符串. 参数可以不是一个真正存在的文件, 甚至可以不是一个文件名
cd dirname $0
和PWD用法
在命令行状态下单纯执行 $ cd dirname $0
是毫无意义的。因为他返回当前路径的"."。 这个命令写在脚本文件里才有作用,他返回这个脚本文件放置的目录,并可以根据这个目录来定位所要运行程序的相对位置(绝对位置除外)。 在/home/admin/test/下新建test.sh内容如下:
cd `dirname $0`
echo `pwd`
然后返回到/home/admin/执行:bash test/test.sh
运行结果: /home/admin/test
这样就可以知道一些和脚本一起部署的文件的位置了,只要知道相对位置就可以根据这个目录来定位,而可以不用关心绝对位置。这样脚本的可移植性就提高了,扔到任何一台服务器,(如果是部署脚本)都可以执行。
bash or zsh 添加环境变量PATH
bash:.bashrc zsh:.zshrc
在最后一行添加以下命令,其中:表示路径分隔符,~/bin就是我们刚才创建的文件路径 export PATH=$PATH:~/bin
这样的话,在~/bin添加一些脚本,就可以直接在别的路径通过名字执行了
Bash shell脚本打印出正在执行的命令
默认情况下,bash脚本不会打印执行的每个命令,这个有时候不太方面。
如下的方法可以让bash脚本打印出执行的命令:
1、在脚本里添加
set -v
或者 #!/bin/bash -v
以加 set -v 最好。
set -v 和 set -o verbose 是一样的
2、添加
set -x
或者 #!/bin/bash -x
3、 bash -v script.sh 或者 bash -x script.sh
Bash Shell中Shift用法
shift可以用来向左移动位置参数。
Shell的名字 $0
第一个参数 $1
第二个参数 $2
第n个参数 $n
所有参数 $@ 或 $*
参数个数 $#
shift默认是shift 1
例:
#----------------------------输出文字-开始---------------------------- #!/bin/bash #Filename: shift.sh
#by www.jbxue.com
until [ -z "$1" ] # Until all parameters used up
do
echo "$@ " shift done
#----------------------------输出文字-结束----------------------------
sh shift.sh 1 2 3 4 5 6 7 8 9
#----------------------------输出文字-开始----------------------------
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
3 4 5 6 7 8 9
4 5 6 7 8 9
5 6 7 8 9
6 7 8 9
7 8 9
8 9
9
#----------------------------输出文字-结束----------------------------
shift 命令:可以使脚本的所有参数位置向左移动一位(删除第一位,第二个参数变成了第一个,以此类推)
因为shell脚本最多定位九个变量,所以需要 shift 来获取超出9个之外的 参数
#! bin/bash
func()
{
#通过while和shift命令一次获取参数值
while (($# > 0))
do
echo "$1"
shift
done
}
func 1 2 3 4 5 6 7 8 9 0
shift 命令会影响到系统变量 $# 的值
shell 文件路径
假设我们定义了一个变量为:
file=/dir1/dir2/dir3/my.file.txt
可以用${ }分别替换得到不同的值:
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt
${file##*.}:删掉最后一个 . 及其左边的字符串:txt
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值)
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
${file:0:5}:提取最左边的 5 个字节:/dir1
${file:5:5}:提取第 5 个字节右边的连续5个字节:/dir2
记忆的方法为:
# 是去掉左边(键盘上#在 $ 的左边)
% 是去掉右边(键盘上% 在$ 的右边)
单一符号是最小匹配;两个符号是最大匹配
也可以对变量值里的字符串作替换:
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt
利用 ${ } 还可针对不同的变数状态赋值(沒设定、空值、非空值): ${file-my.file.txt} :假如 $file 沒有设定,則使用 my.file.txt 作传回值。(空值及非空值時不作处理) ${file:-my.file.txt} :假如 $file 沒有設定或為空值,則使用 my.file.txt 作傳回值。 (非空值時不作处理) ${file+my.file.txt} :假如 $file 設為空值或非空值,均使用 my.file.txt 作傳回值。(沒設定時不作处理) ${file:+my.file.txt} :若 $file 為非空值,則使用 my.file.txt 作傳回值。 (沒設定及空值時不作处理) ${file=my.file.txt} :若 $file 沒設定,則使用 my.file.txt 作傳回值,同時將 $file 賦值為 my.file.txt 。 (空值及非空值時不作处理) ${file:=my.file.txt} :若 $file 沒設定或為空值,則使用 my.file.txt 作傳回值,同時將 $file 賦值為my.file.txt 。 (非空值時不作处理) ${file?my.file.txt} :若 $file 沒設定,則將 my.file.txt 輸出至 STDERR。 (空值及非空值時不作处理)
${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值時不作处理) ${#var} 可计算出变量值的长度:
${#file} 可得到 27 ,因为/dir1/dir2/dir3/my.file.txt 是27个字节
shell产生随机数七种方法
https://blog.csdn.net/taiyang1987912/article/details/39997303
方法1:系统环境变量
echo $RANDOM
生成0-32767之间的整数随机数,若超过5位可以加个固定10位整数,然后进行求余。 生成400000~500000的随机数:
#!/bin/bash
function rand(){
min=$1
max=$(($2-$min+1))
num=$(($RANDOM+1000000000)) #增加一个10位的数再求余
echo $(($num%$max+$min))
}
rnd=$(rand 400000 500000)
echo $rnd
exit 0
方法2:使用awk的随机函数
csh没有$RANDOM,awk刚好能用
awk 'BEGIN{srand();print rand()*1000000}' #可以加上if判断,779644
方法3:openssl rand产生随机数
openssl rand 用于产生指定长度个bytes的随机字符。-base64或-hex对随机字符串进行base64编码或用hex格式显示。
openssl rand -base64 8 | md5sum | cut -c1-8 #八位字母和数字的组合,3a61800e
openssl rand -base64 8 | cksum | cut -c1-8 #八位数字,10784736
方法4:通过时间获得随机数(date)
date +%s%N #生成19位数字,1287764807051101270
date +%s%N | cut -c6-13 #取八位数字,21793709
date +%s%N | md5sum | head -c 8 #八位字母和数字的组合,87022fda
生成1~50的随机数:
#!/bin/bash
function rand(){
min=$1
max=$(($2-$min+1))
num=$(date +%s%N)
echo $(($num%$max+$min))
}
rnd=$(rand 1 50)
echo $rnd
exit 0
方法5:通过系统内唯一数据生成随机数(/dev/random及/dev/urandom)
/dev/random存储系统当前运行的环境的实时数据,可以看作系统某时候的唯一值数据,提供优质随机数。
/dev/urandom是非阻塞的随机数产生器,读取时不会产生阻塞,速度更快、安全性较差的随机数发生器。
cat /dev/urandom | head -n 10 | md5sum | head -c 10 #32f1e953ac
cat /dev/urandom | strings -n 8 | head -n 1 #生成全字符的随机字符串,08?WU$ZU
cat /dev/urandom | sed -e 's/[^a-zA-Z0-9]//g' | strings -n 8 | head -n 1 #生成数字加字母的随机字符串,Ql2q9CXS
其中 strings -n设置字符串的字符数,head -n设置输出的行数。
head-200/dev/urandom| cksum |cut-d" " -f1 #urandom的数据很多使用cat会比较慢,在此使用head读200行,cksum将读取文件内容生成唯一的表示整型数据,cut以” “分割然后得到分割的第一个字段数据
在UNIX操作系统(包括类UNIX系统)中,/dev/random 是一个特殊的设备文件,可以用作随机数发生器或伪随机数发生器。
/dev/urandom
是 /dev/random
一个副本,非阻塞的随机数发生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对 /dev/urandom
的读取操作不会产生阻塞,但其输出的熵可能小于 /dev/random
的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。
常用的生成随机数的方法
tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
该命令生成 32 位的带有 A-Za-z0-9_!@#$%^&*()-+=
的随机数,在 MacOS 中需要指定语言环境为 C 语言才行
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
方法6:读取linux的uuid码
UUID码全称是通用唯一识别码 (Universally Unique Identifier, UUID),UUID格式是:包含32个16进制数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。linux的uuid码也是有内核提供的,在/proc/sys/kernel/random/uuid这个文件内。cat/proc/sys/kernel/random/uuid每次获取到的数据都会不同。
cat /proc/sys/kernel/random/uuid| cksum | cut -f1 -d" " #获取不同的随机整数,1675034933
cat /proc/sys/kernel/random/uuid| md5sum | cut -c1-8 #数字加字母的随机数,d69a7ebf
使用linux uuid 生成100~500随机数:
#!/bin/bash
function rand(){
min=$1
max=$(($2-$min+1))
num=$(cat /proc/sys/kernel/random/uuid | cksum | awk -F ' ' '{print $1}')
echo $(($num%$max+$min))
}
rnd=$(rand 100 500)
echo $rnd
exit 0
方法7:从元素池中随机抽取取
pool=(a b c d e f g h i j k l m n o p q r s t 1 2 3 4 5 6 7 8 9 10)
num=${#pool[*]}
result=${pool[$((RANDOM%num))]}
用于生成一段特定长度的有数字和字母组成的字符串,字符串中元素来自自定义的池子。
#!/bin/bash
length=8
i=1
seq=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
num_seq=${#seq[@]}
while [ "$i" -le "$length" ]
do
seqrand[$i]=${seq[$((RANDOM%num_seq))]}
let "i=i+1"
done
echo "The random string is:"
for j in ${seqrand[@]}
do
echo -n $j
done
echo
csh里生成随机数
# 通过awk
random=$(awk 'BEGIN{srand();print rand()*1000000}')
random=$(echo $random | cut -d '.' -f 1)
# 通过/dev/urandom
random=$(cat /dev/urandom | sed -e 's/[^0-9]//g' | head -n 1)
random=$(echo $random | cut -c 1-8)
shell打包加密成可执行文件
sudo apt install shc
shc -v -r -f echo1 echo1:源文件,源文件必须指定 #!/bin/bash
之类的 echo1.x:目标二进制文件 echo1.x.c:过程C文件 这个工具是将shell脚本转为C语言,然后在打包成二进制文件
shc的反编译UnSHc
github上克隆:git clone https://github.com/yanncam/UnSHc.git,文件夹lastest中有个脚本unshc.sh可以完成反编译功能。
./unshc.sh -h查看使用方法,笔者使用sample里面的例程测试可以。但是笔者觉得这个工具意义不大,除非知道二级制文件是使用shc来编译的,不然反编译出来也不成功。反编译UnSHc对于开发人员来说作用不大。
多条件if判断:与 或
if [[ $a == $b || $c == $d ]]; then
echo OR
fi
if [[ $a == $b && $c == $d ]]; then
echo AND
fi
shell脚本中使用sudo免输密码
方法一:
在shell脚本中需要用root用的来执行指令: sudo 自动输入密码
echo "password" | sudo -S netstat -tlnp
参数 -S:The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.
方法二:
- 打开sudo的配置文件:vim /etc/sudoers
- 在root ALL下行加入:username ALL=(ALL) NOPASSWD: ALL
Shell判断字符串包含关系的几种方法
Shell中判断字符串包含关系的方法:
1、通过grep来判断:
str1="abcdefgh"
str2="def"
result=$(echo $str1 | grep "${str2}")
if [[ "$result" != "" ]]
then
echo "包含"
else
echo "不包含"
fi
2、字符串运算符
str1="abcdefgh"
str2="def"
if [[ $str1 =~ $str2 ]]
then
echo "包含"
else
echo "不包含"
fi
3、利用通配符
str1="abcdefgh"
str2="def"
if [[ $str1 == *$str2* ]]
then
echo "包含"
else
echo "不包含"
fi
4、利用case in 语句
str1="abcdefgh"
str2="def"
case $str1 in
*"$str2"*) echo Enemy Spot ;;
*) echo nope ;;
esa
5、利用替换
str1="abcdefgh"
str2="def"
if [[ ${str1/${str2}//} == $str1 ]]
then
echo "不包含"
else
echo "包含"
fi
if判断时防止参数为空
if[x$1 = x];
当$1为a时
if[x$1 = x]; 实际就会判断 xa = x
这样写的主要目的是当如果写成["$1" = "$2" ]
在 $1,$2为空时会在某些bash版本中出现编译错误所以运用了shell中的字符抵消原则。
文件名带空格
- 使用双引号括起来,模糊匹配时可以
"*\ *"
- 修改IFS,不用空格作为IFS
- 在处理文件名之前,先将空格处理为其它字符,比如
_
重定向到文件时,发生导致“模糊重定向”消息
ambiguous redirect的叫法有: + 模糊重定向 + 歧义重定向
echo $AAAA" "$DDDD" "$MOL_TAG >> ${OUPUT_RESULTS}
上面的写法可能会报错:${OUPUT_RESULTS}: ambiguous redirect
。如果OUPUT_RESULTS
碰巧有空格,j就会出现“歧义重定向”。 解决办法是:用引号括起你的变量。
$ var="file with spaces"
$ echo $AAAA" "$DDDD" "$MOL_TAG >> ${var}
bash: ${var}: ambiguous redirect
$ echo $AAAA" "$DDDD" "$MOL_TAG >> "${var}"
$ cat file\ with\ spaces
aaaa dddd mol_tag
重定向文件名称中的空格会导致“歧义重定向”消息。 例如,如果您重定向到application$(date +%Y%m%d%k%M%S).log
并指定了错误的格式字符,则重定向将在上午10点之前失败。但是,如果您使用application$(date +%Y%m%d%H%M%S).log
,它将会成功。这是因为%k
格式生成上午9点的' 9'
,而%H
生成上午9点的'09'
echo $(date +%Y%m%d%k%M%S)
给了20140626 95138
echo $(date +%Y%m%d%H%M%S)
给了20140626095138
错误的日期可能如下所示:
echo "a" > myapp20140626 95138.log
其中,以下是所需的:
echo "a" > myapp20140626095138.log
另一件可能导致“二义性重定向”的事情是您正在编写的变量名中的\t
\n
\r
也许不是\n\r
?但在谨慎方面犯了错误
尝尝这个
echo "a" > ${output_name//[$'\t\n\r']}
我在分析HTML \t
时遇到了这个问题。
原文:https://cloud.tencent.com/developer/ask/sof/69279
shell脚本中使用sudo免输密码
方法一:
在shell脚本中需要用root用的来执行指令: sudo 自动输入密码
echo "password" | sudo -S netstat -tlnp
参数 -S:The -S (stdin) option causes sudo to read the password from the standard input instead of the terminal device.
方法二:
- 打开sudo的配置文件:vim /etc/sudoers
- 在root ALL下行加入:username ALL=(ALL) NOPASSWD: ALL